package com.edgar.plugin.utils;

import android.util.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by Edgar on 2018/2/1.
 */
public final class MethodUtils {

    private static final String TAG = "MethodUtils";
    private MethodUtils(){}

    public static Method findMethod(Class<?> clazz, String methodName,boolean findSupperClass, Class<?>... parameterType){
        try {
            return clazz.getDeclaredMethod(methodName,parameterType);
        } catch (NoSuchMethodException e) {
            Log.e(TAG,String.format("no such %s",methodName),e);
            if (findSupperClass){
                return findMethod(clazz.getSuperclass(),methodName,true,parameterType);
            }
            return null;
        }
    }

    //======start invoke static method========
    public static Object invokeStaticMethodThrowError(Class<?> clazz, String methodName, Class<?>[] parameterTypes, Object... args)
            throws IllegalAccessException,InvocationTargetException{
        return invokeMethodThrowError(null,findMethod(clazz,methodName,false,parameterTypes),args);
    }

    public static Object invokeStaticMethod(Class<?> clazz, String methodName,Class<?>[] parameterTypes,Object... args){
        return invokeStaticMethod(findMethod(clazz,methodName,false,parameterTypes),args);
    }

    public static Object invokeStaticMethod(Method method,Object... args){
        return invoke(null,method,args);
    }

    //=======end invoke static method========

    //========start invoke method==========

    /**
     * 反射执行方法,此方法会抛出异常
     * @param object 方法所在的对象
     * @param methodName 方法名
     * @param parameterTypes 参数类型
     * @param args 参数值
     * @return 返回方法执行的结果
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object invokeMethodThrowError(Object object, String methodName, Class<?>[] parameterTypes, Object... args)
            throws InvocationTargetException, IllegalAccessException {
        return invokeMethodThrowError(object, findMethod(object.getClass(),methodName,false,parameterTypes),args);
    }

    /**
     * 反射执行方法
     * @param object 方法所在的对象
     * @param methodName 方法名
     * @param parameterTypes 参数类型集合
     * @param args 参数
     * @return 返回执行的结果
     */
    public static Object invokeMethod(Object object, String methodName, Class<?>[] parameterTypes,Object... args){
        return invoke(object, findMethod(object.getClass(),methodName,false,parameterTypes),args);
    }

    /**
     * 反射执行方法
     * @param targetClass 方法的目标类型
     * @param object 执行的接收对象
     * @param methodName 方法名
     * @param parameterTypes 参数类型集合
     * @param args 参数值
     * @return 返回执行结果
     */
    public static Object invokeMethod(Class<?> targetClass,Object object,String methodName,Class<?>[] parameterTypes,Object... args){
        return invoke(object,findMethod(targetClass,methodName,false,parameterTypes),args);
    }

    //=======end invoke method==========

    private static Object invokeMethodThrowError(Object object, Method method, Object... args)throws IllegalAccessException,InvocationTargetException{
        if (method == null) return null;
        method.setAccessible(true);
        return method.invoke(object,args);
    }

    private static Object invoke(Object object,Method method,Object... args){
        try {
            if (method == null) return null;
            method.setAccessible(true);
            return method.invoke(object,args);
        } catch (IllegalAccessException e) {
            Log.e(TAG,String.format("%s illegal access",method.getName()),e);
        } catch (InvocationTargetException e) {
            Log.e(TAG,String.format("%s invoke failed",method.getName()),e);
        }
        return null;
    }
}
